package api

import (
	"easyShop/core/database/mysql"
	"easyShop/model"
	"easyShop/services"
	"easyShop/utils"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/mojocn/base64Captcha"
	"gorm.io/gorm"
	"strconv"
)

type UserController struct {
}

// AuthLogin 小程序openid自动登录
func (p UserController) AuthLogin(c *gin.Context) {
	type wxUserInfo struct {
		AvatarUrl string `from:"avatar_url" json:"avatarUrl,omitempty"`
		City      string `from:"city" json:"city,omitempty"`
		Country   string `from:"country" json:"country,omitempty"`
		Gender    *uint8 `from:"gender" json:"gender,omitempty" binding:"required"`
		Language  string `from:"language" json:"language,omitempty"`
		NickName  string `from:"nick_name" json:"nickName,omitempty"`
		Province  string `from:"province" json:"province,omitempty"`
	}
	// 验证器
	type validatorRule struct {
		OpenId   string      `form:"openid" json:"openid" binding:"required"`
		UserInfo *wxUserInfo `form:"userinfo" json:"userinfo" binding:"required"`
	}
	var postJson validatorRule
	if err := c.ShouldBindWith(&postJson, binding.JSON); err != nil {
		c.JSON(200, gin.H{
			"code":    500,
			"data":    nil,
			"message": err.Error(),
		})
		return
	}

	// set user info
	var userInfo model.User
	userInfo.Openid = postJson.OpenId
	userInfo.Nickname = postJson.UserInfo.NickName
	userInfo.AvatarUrl = postJson.UserInfo.AvatarUrl
	userInfo.City = postJson.UserInfo.City
	userInfo.Province = postJson.UserInfo.Province
	userInfo.Country = postJson.UserInfo.Country
	userInfo.Language = postJson.UserInfo.Language
	userInfo.Sex = *postJson.UserInfo.Gender

	token, serverErr := services.AuthLogin(&userInfo)

	if serverErr != nil {
		c.JSON(200, gin.H{
			"code":    500,
			"data":    nil,
			"message": serverErr.Error(),
		})
		return
	}
	c.JSON(200, gin.H{
		"code":    200,
		"data":    map[string]interface{}{"token": token, "userinfo": userInfo},
		"message": "success",
	})
}

func (p UserController) GetUserInfo(c *gin.Context) {
	idStr := c.Query("id")
	id, _ := strconv.Atoi(idStr)
	user, errorMsg := services.GetUserInfo(int64(id))
	if errorMsg != "" {
		c.JSON(200, gin.H{
			"code":    500,
			"message": errorMsg,
		})
		return
	}

	c.JSON(200, gin.H{
		"code":    200,
		"message": "success",
		"data":    user,
	})
}

func (p UserController) UpdateUserInfo(c *gin.Context) {
	con := mysql.GetConnect()
	con.Model(&model.User{}).Updates(model.User{Id: 0, Username: "", Sex: 2})
}

func (p UserController) Register(c *gin.Context) {
	// 验证器
	type validatorRule struct {
		username    string `form:"username" binding:"required"`
		password    string `form:"password" binding:"required"`
		captchaId   string `form:"captcha_id" binding:"required"`
		captchaCode string `form:"captcha_code" binding:"required"`
	}
	var val validatorRule
	if err := c.ShouldBindWith(&val, binding.FormPost); err != nil {
		c.JSON(200, gin.H{
			"code":    500,
			"data":    nil,
			"message": err.Error(),
		})
		return
	}

	// 检验验证码
	captchaId := c.PostForm("captcha_id")
	captchaCode := c.PostForm("captcha_code")
	username := c.PostForm("username")
	password := c.PostForm("password")

	// 捕获异常
	defer func() {
		err := recover() //	recover 内置函数捕获异常
		if err != nil {  // 	nil 是 err 的零值
			c.JSON(200, gin.H{
				"code":    200,
				"data":    []string{},
				"message": err,
			})
			return
		}
	}()

	err := services.Register(username, password, captchaId, captchaCode)

	if err != nil {
		c.JSON(200, gin.H{
			"code":    500,
			"data":    nil,
			"message": err.Error(),
		})
		return
	}

	c.JSON(200, gin.H{
		"code":    200,
		"data":    []string{},
		"message": "注册成功",
	})
	return
}

func (p UserController) GetBase64Captcha(c *gin.Context) {
	var store = base64Captcha.DefaultMemStore
	// 生成默认数字的driver
	driver := base64Captcha.NewDriverDigit(60, 200, 6, 0.7, 80)
	cp := base64Captcha.NewCaptcha(driver, store)
	if id, base64Data, err := cp.Generate(); err != nil {
		c.JSON(200, gin.H{
			"code":    500,
			"message": "验证码获取失败",
		})
	} else {
		c.JSON(200, gin.H{
			"code":    200,
			"message": "验证码获取成功",
			"data": gin.H{
				"captcha_id": id,
				"base64":     base64Data,
			},
		})
	}
}

func (p UserController) CheckCaptcha(c *gin.Context) {
	type validatorRule struct {
		CaptchaId   string `form:"captcha_id" json:"captcha_id" binding:"required"`
		CaptchaCode string `form:"captcha_code" json:"captcha_code" binding:"required"`
	}
	var val validatorRule
	if err := c.ShouldBindWith(&val, binding.Query); err != nil {
		c.JSON(200, gin.H{
			"code":    500,
			"data":    nil,
			"message": err.Error(),
		})
		return
	}

	captchaId := c.Query("captcha_id")
	captchaCode := c.Query("captcha_code")
	var store = base64Captcha.DefaultMemStore
	if store.Verify(captchaId, captchaCode, true) {
		c.JSON(200, gin.H{
			"code":    500,
			"message": "验证码正确",
		})
	} else {
		c.JSON(200, gin.H{
			"code":    500,
			"message": "验证码错误",
		})
	}
}

func (p UserController) GetUserList(c *gin.Context) {
	pageParam := c.Query("page")
	page, _ := strconv.Atoi(pageParam)
	userList, err := services.GetUserList(page)
	if err != "" {
		c.JSON(200, gin.H{
			"code":    500,
			"message": err,
		})
		return
	}

	c.JSON(200, gin.H{
		"code":    200,
		"message": "success",
		"data":    userList,
	})
}

func (p UserController) Login(c *gin.Context) {
	// 验证器
	type validatorRule struct {
		Username string `form:"username" binding:"required"`
		Password string `form:"password" binding:"required"`
	}
	var val validatorRule
	if err := c.ShouldBindWith(&val, binding.Form); err != nil {
		c.JSON(200, gin.H{
			"code":    500,
			"data":    nil,
			"message": err.Error(),
		})
		return
	}
	username := c.PostForm("username")
	password := c.PostForm("password")
	// 调用登录服务
	token, err := services.Login(username, password)
	if err != nil {
		c.JSON(200, gin.H{
			"code":    500,
			"message": err.Error(),
			"data":    nil,
		})
		return
	}
	c.JSON(200, gin.H{
		"code":    200,
		"message": "success",
		"token":   token,
	})
}

func (p UserController) CheckToken(c *gin.Context) {
	token := c.Query("token")
	r, _ := services.JwtDecode(token)
	fmt.Print(r)
}

func (p UserController) GetOpenId(c *gin.Context) {
	var errMsg string
	type ApiStruct struct {
		Openid     string `json:"openid"`
		SessionKey string `json:"session_key"`
		Unionid    string `json:"unionid"`
		Errcode    int    `json:"errcode"`
		Errmsg     string `json:"errmsg"`
	}
	type Params struct {
		Code string `json:"code"`
	}
	var params Params
	var apiResult ApiStruct
	getParamsError := c.BindJSON(&params)
	if getParamsError != nil {
		c.JSON(200, gin.H{
			"code":    500,
			"message": getParamsError.Error(),
			"data":    []string{},
		})
		return
	}

	resByte, _ := utils.Get("https://api.weixin.qq.com/sns/jscode2session?appid=wx1f1ceb233eff5bab&secret=d07cc52353ffe5dae355ecb2d8640449&js_code=" + params.Code + "&grant_type=authorization_code")

	mysqlConnect := mysql.GetConnect()
	var userInfo model.User
	var tx *gorm.DB

	unErr := json.Unmarshal(resByte, &apiResult)
	if unErr != nil {
		errMsg = unErr.Error()
		goto Err
	}

	if apiResult.Errcode != 0 {
		errMsg = apiResult.Errmsg
		goto Err
	}

	tx = mysqlConnect.Where("openid = ?", apiResult.Openid).Find(&userInfo)

	if tx.Error != nil {
		errMsg = tx.Error.Error()
		goto Err
	}

	c.JSON(200, gin.H{
		"code":    200,
		"message": "success",
		"data":    map[string]interface{}{"openid": apiResult.Openid, "userinfo": userInfo},
	})
	return

Err:
	c.JSON(200, gin.H{
		"code":    500,
		"message": errMsg,
		"data":    []string{},
	})
	return
}

func (p UserController) PerfectUserProfile(c *gin.Context) {
	var businessError error
	// 验证器
	type validatorRule struct {
		Username string `json:"username" binding:"required"`
		Password string `json:"password" binding:"required"`
	}
	var val validatorRule
	if err := c.ShouldBindJSON(&val); err != nil {
		c.JSON(200, gin.H{
			"code":    500,
			"data":    nil,
			"message": err.Error(),
		})
		return
	}

	userInfoData, _ := c.Get("userInfo")
	var userInfo model.User
	businessError = utils.MapToStruct(userInfoData.(map[string]interface{}), &userInfo)
	if businessError != nil {
		goto errHandle
	}

	businessError = services.PerfectUserProfile(userInfo.Id, val.Username, val.Password)
	if businessError != nil {
		goto errHandle
	}

	c.JSON(200, gin.H{
		"code":    200,
		"data":    map[string]interface{}{"username": val.Username},
		"message": "success",
	})

	return

errHandle:
	c.JSON(200, gin.H{
		"code":    500,
		"data":    nil,
		"message": businessError.Error(),
	})
	return

}

func (p UserController) GetAssets(c *gin.Context) {
	userInfoData, _ := c.Get("userInfo")
	var userInfo model.User
	var BusinessErr error
	var result map[string]interface{}
	BusinessErr = utils.MapToStruct(userInfoData.(map[string]interface{}), &userInfo)
	if BusinessErr != nil {
		goto errHandle
	}

	result = services.GetAssets(userInfo.Id)

	c.JSON(200, gin.H{
		"code":    200,
		"data":    result,
		"message": "success",
	})
	return

errHandle:
	c.JSON(200, gin.H{
		"code":    500,
		"data":    nil,
		"message": BusinessErr.Error(),
	})
	return
}
